package org.fjsei.yewu.config.datasource;

import org.fjsei.yewu.jpa.CustomRepositoryFactoryBean;
import org.fjsei.yewu.jpa.ExtendedJpaRepositoryImpl;
import org.hibernate.cfg.Environment;
import org.infinispan.hibernate.cache.v62.InfinispanRegionFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.repository.config.BootstrapMode;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;

import jakarta.annotation.Resource;
import jakarta.persistence.EntityManager;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;

import javax.sql.DataSource;
import java.util.Map;
import java.util.Properties;


//解决了问题：@ManyToMany或@OneToMany的Many多的那一方，一定用Set容器来存放，而不能用List集合。

//对接：旧平台库
//允许把@Configuration注释掉，关闭数据源； 因upsertAll需改；
@Configuration
@EnableJpaRepositories(
        repositoryBaseClass = ExtendedJpaRepositoryImpl.class,
        repositoryFactoryBeanClass = CustomRepositoryFactoryBean.class,
        bootstrapMode= BootstrapMode.LAZY,
        entityManagerFactoryRef = "entityManagerFactoryFjtj",
        basePackages ={"org.fjsei.yewu.entity.fjtj"}
)
public class FjtjConfig {
    @Value("${app.datasource.fjtj.dialect:org.hibernate.dialect.CockroachDialect}")
    private  String  dialect="";
    /* 旧的平台运行库;  app.datasource.fjtj是配置文件的某项。
     */
    @Bean(name = "dataSourcePropertiesFjtj")
    @Qualifier("dataSourcePropertiesFjtj")
    @ConfigurationProperties(prefix="app.datasource.fjtj")
    public DataSourceProperties dataSourcePropertiesFjtj() {
        return new DataSourceProperties();
    }

    @Bean(name = "fjtjDataSource")
    @Qualifier("fjtjDataSource")
    //@ConfigurationProperties(prefix="app.datasource.fjtj")
    public DataSource fjtjDataSource(@Qualifier("dataSourcePropertiesFjtj") DataSourceProperties dataSourcePropertiesFjtj) {
        return dataSourcePropertiesFjtj.initializeDataSourceBuilder().build();
    }


    @Bean(name = "fjtjJdbcTemplate")
    @Qualifier("fjtjJdbcTemplate")
    public JdbcTemplate fjtjJdbcTemplate(@Qualifier("fjtjDataSource") DataSource dataSource) {
        return new JdbcTemplate(dataSource);
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor() {
        return new PersistenceExceptionTranslationPostProcessor();
    }
    //最后一步执行的：当前配置有连接数据库。
    @Primary
    @Bean(name = "entityManagerFjtj")
    public EntityManager entityManager(EntityManagerFactoryBuilder builder,
                                       @Qualifier("entityManagerFactoryFjtj")  LocalContainerEntityManagerFactoryBean entityManagerFactoryFjtj) {
        return entityManagerFactoryFjtj.getObject().createEntityManager();
    }

    @Resource
    private JpaProperties jpaProperties;

    private Map<String, Object> getVendorProperties() {
        return null; //jpaProperties.getHibernateProperties(new HibernateSettings());
    }

    /**
     * 设置实体类所在位置
     */
//    @Bean(name = "entityManagerFactoryFjtj")
//    public LocalContainerEntityManagerFactoryBean entityManagerFactoryFjtj(EntityManagerFactoryBuilder builder,
//                   @Qualifier("fjtjDataSource") DataSource fjtjDataSource ) {
//        return builder
//                .dataSource(fjtjDataSource)
//                .packages("org.fjsei.yewu.entity.fjtj")
//                .persistenceUnit("fjtjPersistenceUnit")
//                .build();
//    }

    //独立数据库，不支持跨越多数据库的事务。 实际构造 EntityManagerFactory
    @Bean(name = "entityManagerFactoryFjtj")
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryFjtj() {
        LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
        emf.setDataSource(fjtjDataSource(dataSourcePropertiesFjtj()));           //dataSourcePropertiesFjtj() fjtjDataSource()
        emf.setPackagesToScan("org.fjsei.yewu.entity.fjtj");     //不能省略
        /*从跟踪AbstractEntityManagerFactoryBean.jpaPropertyMap:发现其他数据库的配置29个属性，我这里才有14属性的。导致查询缓冲实际没有开动问题！
        所以必须添加上低下这句：把基本的共同配置属性也带上！
        "hibernate.cache.infinispan.cfg" -> "infinispan-dev.xml"
        "hibernate.cache.region.factory_class" -> "infinispan"
         但是导致spring.jpa.properties.hibernate.search.backend.hosts: localhost传递给HibernateSearch报错 hibernate.search配置被冲没掉？
        HibernateSearch应该走 hibernate.properties  pesistence.xml 去配置ES服务端,不要放"spring.jpa.properties.hibernate..."这。
        * */
        emf.setJpaPropertyMap(jpaProperties.getProperties());
        emf.setJpaProperties(jpaVendorProperties());
        emf.setJpaVendorAdapter(jpaVendorAdapter());
        //emf.getJpaPropertyMap().put(Environment.DIALECT, CockroachDB201Dialect.class.getName());
        emf.setPersistenceUnitName("fjtjPersistenceUnit");
        return emf;
    }
    /** 和application.yml里面相同配置比：这里会覆盖对方的；
     * 这个覆盖掉jpaProperties.getProperties()相同属性。
     * */
    private Properties jpaVendorProperties() {
        return new Properties() {
            {
                setProperty(Environment.GENERATE_STATISTICS, Boolean.TRUE.toString());
                setProperty(Environment.LOG_SESSION_METRICS, Boolean.TRUE.toString());    //FALSE无法输出慢sql日志
                //JPA慢SQL侦查 SlowQuery: 277 milliseconds. SQL: 'HikariProxyPreparedStatement [； ？277=可能不包含fetching的ms? hibernate.session.events.log.LOG_QUERIES_SLOWER_THAN_MS
//                setProperty(Environment.LOG_SLOW_QUERY, "100");     //不添加不行！其它的3个数据源直接会采用application.yml配置LOG_QUERIES_SLOWER_THAN_MS。

                setProperty(Environment.USE_MINIMAL_PUTS, Boolean.TRUE.toString());
                //CRDB例子引入: setProperty(Environment.USE_SECOND_LEVEL_CACHE, Boolean.FALSE.toString());
                //CRDB例子引入: setProperty(Environment.CACHE_REGION_FACTORY, NoCachingRegionFactory.class.getName());
                setProperty(Environment.CACHE_REGION_FACTORY, InfinispanRegionFactory.class.getName());
                setProperty(Environment.STATEMENT_BATCH_SIZE, "250");
                setProperty(Environment.BATCH_VERSIONED_DATA, Boolean.TRUE.toString());
                setProperty(Environment.ORDER_INSERTS, Boolean.TRUE.toString());
                setProperty(Environment.ORDER_UPDATES, Boolean.TRUE.toString());
                setProperty(Environment.FORMAT_SQL, Boolean.FALSE.toString());       //和application.yml里面相同配置比：这里还不如对方的优先；

                // Mutes Postgres JPA Error (Method org.postgresql.jdbc.PgConnection.createClob() is not yet implemented).
                setProperty(Environment.NON_CONTEXTUAL_LOB_CREATION, Boolean.TRUE.toString());
                /* 具体底层数据库相关！ "hibernate.dialect"   H2Dialect.class.getName()
                    spring.jpa.database-platform=
                    spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.Oracle12cDialect
                datasource:sei: org.hibernate.dialect.MySQLDialect改成.MySQL5Dialect才行,去掉driver-class-name=‘’;
                */
                setProperty(Environment.DIALECT, dialect);
                //HBM2DDL_CREATE_NAMESPACES = "hibernate.hbm2ddl.create_namespaces";
            }
        };
    }

    /**物理数据库：类型这里已经配置，
     * hikari.pool或 ttddyy.dsproxy 记住? postgresql.util.PSQLException: Connection to 192.168.171.3:26257
     * */
    private JpaVendorAdapter jpaVendorAdapter() {
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        //可定制 :生产新字段新表
        vendorAdapter.setGenerateDdl(jpaProperties.isGenerateDdl());
        //所有sql都进入日志:太多了  true  false
//        vendorAdapter.setShowSql(isShowSql);     //和application.yml里面相同配置比：这里比对方的设置优先；
        /* 具体底层数据库相关
        vendorAdapter.setDatabasePlatform(CockroachDB201Dialect.class.getName());
        vendorAdapter.setDatabase(Database.POSTGRESQL); */
        return vendorAdapter;
    }
}
